package com.group.project.hrms.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.group.project.hrms.entity.*;
import com.group.project.hrms.entity.ResultEntity.DayAdjustRecord;
import com.group.project.hrms.entity.ResultEntity.FrontLineMonthlyReport;
import com.group.project.hrms.entity.ResultEntity.ResultEntity;
import com.group.project.hrms.entity.UsefulEntity.DateInMonthEntity;
import com.group.project.hrms.entity.UsefulEntity.DateRangeEntity;
import com.group.project.hrms.service.*;
import com.group.project.hrms.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 该控制器为一线主管专用站点的Web数据模型控制器，用于所有该站点的API数据交互
 */
@Slf4j
@Controller
@EnableScheduling
public class SupervisorWebController {

    @Autowired
    private IFrontLineVacationRecordService iFrontLineVacationRecordService;

    @Autowired
    private IFrontLineSupervisorDeptsService iFrontLineSupervisorDeptsService;

    @Autowired
    private IFrontLineDayAdjustRecordService iFrontLineDayAdjustRecordService;

    @Autowired
    private IContactBasicService iContactBasicService;

    @Autowired
    private IContactBasicDeptInfoService iContactBasicDeptInfoService;

    @Autowired
    private IDingVacationTypeService iDingVacationTypeService;

    @Autowired
    private IAttendanceGroupDeptsService iAttendanceGroupDeptsService;

    @Autowired
    private IAttendanceGroupStaffsService iAttendanceGroupStaffsService;

    @Autowired
    private IAttendanceShiftInfoService iAttendanceShiftInfoService;

    @Autowired
    private IAttendanceGroupInfoService iAttendanceGroupInfoService;

    @Autowired
    private ICheckPointInfoService iCheckPointInfoService;

    @Autowired
    private IRestTimeSettingsService iRestTimeSettingsService;

    @Autowired
    private IHolidayRecordService iHolidayRecordService;

    @Autowired
    private IOvertimeRulesService iOvertimeRulesService;

    @Autowired
    private IDingClockRecordService iDingClockRecordService;

    @Autowired
    private IAttendanceGroupStaffAdjustRecordService iAttendanceGroupStaffAdjustRecordService;

    @Autowired
    private BasicInfoUtil basicInfoUtil;

    @Autowired
    private DateUtil dateUtil;

    @Autowired
    private AttendanceUtil attendanceUtil;

    @Autowired
    private DingAccessUtils dingAccessUtils;

    @Autowired
    private LogUtil logUtil;

    /**
     * 该方法为一线主管使用的Web端页面初始化数据，即在登录之后的数据加载
     * @param map
     * @param request
     * @return
     */
    @RequestMapping("/hrms/supervisor/initPageData")
    @ResponseBody
    public ResultEntity initPageData(@RequestBody Map map, HttpServletRequest request){
        //创建结果集对象
        ResultEntity resultEntity = new ResultEntity();
        Map<String, Object> targetMap = new HashMap<>();
        List<Map> list = new ArrayList<>();

        //获取用户传入的数据
        Object dateString = map.get("dateString"); //格式为2022-04-11
        Date userDate = dateUtil.formatStringToDate(dateString + " 23:00:00");

        //获取请求中的在创建Token时注入的属性
        Object contactID = request.getAttribute("contactId");
        Object staffName = request.getAttribute("staffName");


        try{
            //获取假勤类型信息
            List<DingVacationType> vacationTypes = iDingVacationTypeService.selectAllDingVacationType();

            //获取人员和部门基本信息
            List<ContactBasic> contactBasicList = iContactBasicService.selectAllContactBasicByStaffStatus(1); //正式1、离职2
            List<ContactBasicDeptInfo> contactBasicDeptInfoList = iContactBasicDeptInfoService.selectAllContactBasicDeptInfo();
            //获取该主管下对应的部门IDs
            List<Long> depts = JSONArray.parseArray(iFrontLineSupervisorDeptsService.selectFrontLineSupervisorDeptsBySID(contactID.toString()).getDeptIds(), Long.class);
            //获取这些部门对应的人员信息
            List<ContactBasic> basics = basicInfoUtil.doGetAllContactsByDeptIDs(contactBasicList, contactBasicDeptInfoList, depts);

            //获取用户传入日期的打卡数据
            String checkClockDateFrom = dateString + " 00:00:00";
            String checkClockDateTo = dateString + " 23:59:59";
            List<DingClockRecord> clockRecords = this.getDingClockRecords(basics, checkClockDateFrom, checkClockDateTo);
            Map<String, List<DingClockRecord>> userClockMap = attendanceUtil.getDingClockRecordMap(clockRecords);

            //获取用户传入日期的上一日的打卡数据 - 支持夜班
            //Date lastDate = dateUtil.dateAddOne(dateUtil.formatStringToDate(checkClockDateFrom), -1);
            //int year = dateUtil.getYearByDate(lastDate);
            //int month = dateUtil.getMonthByDate(lastDate);
            //int day = dateUtil.getDayByDate(lastDate);
            //String lastDateString = year + "-" + (month < 10 ? "0" + month : month) + "-" + (day < 10 ? "0" + day : day);
            //System.out.println(lastDateString);
            //String lastCheckClockDateFrom = lastDateString + " 00:00:00";
            //String lastCheckClockDateTo = lastDateString + " 23:59:59";
            //List<DingClockRecord> lastDayClockRecords = this.getDingClockRecords(basics, lastCheckClockDateFrom, lastCheckClockDateTo);
            //Map<String, List<DingClockRecord>> userLastDayClockMap = attendanceUtil.getDingClockRecordMap(lastDayClockRecords);

            //获取用户传入日期的下一日的打卡数据 - 支持夜班
            Date nextDate = dateUtil.dateAddOne(dateUtil.formatStringToDate(checkClockDateFrom), 1);
            int year = dateUtil.getYearByDate(nextDate);
            int month = dateUtil.getMonthByDate(nextDate);
            int day = dateUtil.getDayByDate(nextDate);
            String nextDateString = year + "-" + (month < 10 ? "0" + month : month) + "-" + (day < 10 ? "0" + day : day);
            //System.out.println(nextDateString);
            String nextCheckClockDateFrom = nextDateString + " 00:00:00";
            String nextCheckClockDateTo = nextDateString + " 23:59:59";
            List<DingClockRecord> nextDayClockRecords = this.getDingClockRecords(basics, nextCheckClockDateFrom, nextCheckClockDateTo);
            Map<String, List<DingClockRecord>> userNextDayClockMap = attendanceUtil.getDingClockRecordMap(nextDayClockRecords);


            //获取部门或者人员的考勤组信息，加载考勤规则
            List<AttendanceGroupInfo> groupInfoList = iAttendanceGroupInfoService.selectAllAttendanceGroupInfo();
            Map<String, AttendanceGroupInfo> groupInfoMap = attendanceUtil.getAttendanceGroupInfoMap(groupInfoList);

            List<AttendanceShiftInfo> shiftInfoList = iAttendanceShiftInfoService.selectAllAttendanceShiftInfo();
            Map<String, AttendanceShiftInfo> shiftInfoMap = attendanceUtil.getAttendanceShiftInfoMap(shiftInfoList);

            List<CheckPointInfo> checkPointInfoList = iCheckPointInfoService.selectAllCheckPointInfo();
            Map<String, CheckPointInfo> checkPointInfoMap = attendanceUtil.getCheckPointInfoMap(checkPointInfoList);

            List<RestTimeSettings> restTimeSettingsList = iRestTimeSettingsService.selectAllRestTimeSettings();
            Map<String, RestTimeSettings> restTimeSettingsMap = attendanceUtil.getRestTimeSettingsMap(restTimeSettingsList);

            List<OvertimeRules> overtimeRulesList = iOvertimeRulesService.selectAllOvertimeRules();
            Map<String, OvertimeRules> overtimeRulesMap = attendanceUtil.getOvertimeRulesMap(overtimeRulesList);

            List<AttendanceGroupDepts> groupDeptsList = iAttendanceGroupDeptsService.selectAllAttendanceGroupDepts();
            Map<String, String> groupDeptsMap = attendanceUtil.getGroupDeptMap(groupDeptsList);

            List<AttendanceGroupStaffs> groupStaffsList = iAttendanceGroupStaffsService.selectAllAttendanceGroupStaffs();
            Map<String, String> groupStaffsMap = attendanceUtil.getGroupStaffMap(groupStaffsList);

            List<AttendanceGroupStaffAdjustRecord> staffAdjustRecords = iAttendanceGroupStaffAdjustRecordService.selectAttendanceGroupStaffAdjustRecordByTwoMonth(dateUtil.getMonthStrByDate(userDate), dateUtil.getNextMonthStrByDate(userDate));


            //获取每日加班动态调整记录
            List<FrontLineDayAdjustRecord> adjustRecords = iFrontLineDayAdjustRecordService.selectFrontLineDayAdjustRecordByMonth(dateString.toString());
            Map<String, List<FrontLineDayAdjustRecord>> adjustRecordMap = attendanceUtil.getFrontLineDayAdjustRecordMap(adjustRecords);

            //获取该主管管理下的人员请休假记录
            List<FrontLineVacationRecord> vacationRecords = this.getVacationRecordsByContactsAndMonth(basics, iFrontLineVacationRecordService.selectFrontLineVacationRecordByMonth(dateString.toString().substring(0, 7)));

            //计算日动态调整前端页面需展示的数据集合
            List<DayAdjustRecord> dayAdjustRecordList = new ArrayList<>();
            if(null != basics && basics.size() != 0){
                for (int i = 0; i < basics.size(); i++) {
                    DayAdjustRecord dayAdjustRecord = new DayAdjustRecord();
                    dayAdjustRecord.setKey(i + 1);
                    ContactBasic cb = basics.get(i);
                    List<DingClockRecord> userCheckClocks = userClockMap.get(cb.getDingUserid());
                    List<DingClockRecord> userNextDayCheckClocks = userNextDayClockMap.get(cb.getDingUserid());
                    String attendanceGroupID = null;
                    if(groupStaffsMap.size() != 0){
                        if(null != staffAdjustRecords && staffAdjustRecords.size() != 0){ //当存在调整记录时，应该判断生效日期来获取考勤组ID
                            AttendanceGroupStaffAdjustRecord casualRecord1 = null; //小于用户传入的日期中的最大值
                            AttendanceGroupStaffAdjustRecord casualRecord2 = null; //大于用户传入的日期中的最小值
                            for (AttendanceGroupStaffAdjustRecord record : staffAdjustRecords
                                 ) {
                                if(cb.getContactId().equals(record.getContactId())){
                                    if(record.getDateInForce().getTime() < userDate.getTime()){ //寻找生效日期小于用户传入的日期中的最大值
                                        if(casualRecord1 == null){
                                            casualRecord1 = record;
                                        }else {
                                            if(record.getDateInForce().getTime() > casualRecord1.getDateInForce().getTime()){
                                                casualRecord1 = record;
                                            }
                                        }
                                    }
                                    if(record.getDateInForce().getTime() > userDate.getTime()){ //寻找生效日期大于用户传入的日期中的最小值
                                        if(casualRecord2 == null){
                                            casualRecord2 = record;
                                        }else {
                                            if(record.getDateInForce().getTime() < casualRecord2.getDateInForce().getTime()){
                                                casualRecord2 = record;
                                            }
                                        }
                                    }
                                }
                            }
                            if(null != casualRecord1){
                                attendanceGroupID = casualRecord1.getAttendanceGroupId();
                            }else if(null != casualRecord2){
                                attendanceGroupID = casualRecord2.getPreviousGroupId();
                            }else{
                                attendanceGroupID = groupStaffsMap.get(cb.getContactId());
                            }
                        }else {
                            attendanceGroupID = groupStaffsMap.get(cb.getContactId());
                        }
                    }
                    if(null == attendanceGroupID){
                        JSONArray deptIDArray = JSONArray.parseArray(cb.getDept());
                        String deptID = deptIDArray.getString(0);
                        attendanceGroupID = groupDeptsMap.get(deptID);
                    }
                    if(null != attendanceGroupID){
                        AttendanceGroupInfo groupInfo = groupInfoMap.get(attendanceGroupID);
                        AttendanceShiftInfo shiftInfo = shiftInfoMap.get(groupInfo.getAttendanceShiftId());
                        OvertimeRules overtimeRules = overtimeRulesMap.get(groupInfo.getRulesId());
                        Date onDuty = dateUtil.getDateByPointDate(dateString.toString(), checkPointInfoMap.get(shiftInfo.getStartCheckPointId()).getStandardTime());
                        Date onDutyCheckStart = dateUtil.getDateByPointDate(dateString.toString(), checkPointInfoMap.get(shiftInfo.getStartCheckPointId()).getStartTime());
                        Date onDutyCheckEnd = dateUtil.getDateByPointDate(dateString.toString(), checkPointInfoMap.get(shiftInfo.getStartCheckPointId()).getEndTime());
                        Date offDuty = dateUtil.getDateByPointDate(dateString.toString(), checkPointInfoMap.get(shiftInfo.getEndCheckPointId()).getStandardTime());
                        Date offDutyCheckStart = dateUtil.getDateByPointDate(dateString.toString(), checkPointInfoMap.get(shiftInfo.getEndCheckPointId()).getStartTime());
                        Date offDutyCheckEnd = dateUtil.getDateByPointDate(dateString.toString(), checkPointInfoMap.get(shiftInfo.getEndCheckPointId()).getEndTime());

                        //获取最小旷工时间（分钟）
                        int minNeglectWorkHours = shiftInfo.getMinNeglectWorkHours();

                        //计算班次休息时段总小时数和加班休息时段总小时数
                        long restTimeInShiftMills = 0L;
                        String restIDsInShift = shiftInfo.getRestTimeIds();
                        String restIDSInOverTime = null;
                        if(null != overtimeRulesMap.get(groupInfo.getRulesId())){
                            restIDSInOverTime = overtimeRulesMap.get(groupInfo.getRulesId()).getRestTimeIds();
                        }
                        if(null != restIDsInShift){
                            JSONArray array = JSONArray.parseArray(restIDsInShift);
                            for (Object obj : array
                                 ) {
                                RestTimeSettings restTimeSettings = restTimeSettingsMap.get(obj);
                                Date restStart = dateUtil.getDateByPointDate(dateString.toString(), restTimeSettings.getStartTime());
                                Date restEnd = dateUtil.getDateByPointDate(dateString.toString(), restTimeSettings.getEndTime());
                                restTimeInShiftMills = restTimeInShiftMills + (restEnd.getTime() - restStart.getTime());
                            }
                        }


                        String clockString = "";
                        boolean isNight = false;
                        if(onDuty.getTime() > offDuty.getTime()){ //夜班 (已经改为向后一天取值)
                            //onDuty = dateUtil.getDateByPointDate(lastDateString, onDuty);
                            //onDutyCheckStart = dateUtil.getDateByPointDate(lastDateString, onDutyCheckStart);
                            //onDutyCheckEnd = dateUtil.getDateByPointDate(lastDateString, onDutyCheckEnd);

                            offDuty = dateUtil.getDateByPointDate(nextDateString, offDuty);
                            offDutyCheckStart = dateUtil.getDateByPointDate(nextDateString, offDutyCheckStart);
                            offDutyCheckEnd = dateUtil.getDateByPointDate(nextDateString, offDutyCheckEnd);

                            if(null != userNextDayCheckClocks && null != userCheckClocks){
                                //添加昨日打卡时间并将昨日打卡时间放在前面
                                userNextDayCheckClocks.addAll(userCheckClocks);
                                userCheckClocks = userNextDayCheckClocks;
                            }
                            isNight = true;
                            //System.out.println(cb.getStaffName() + " 是夜班人员");
                        }
                        if(null != userCheckClocks && userCheckClocks.size() != 0){
                            Date startDate = null;
                            Date midDate = null;
                            Date endDate = null;
                            for (int j = 0; j < userCheckClocks.size(); j++) {
                                Date userCheckDate = userCheckClocks.get(j).getUserchecktime();
                                if(j == userCheckClocks.size() - 1){ //使用查询日期的该员工下班的最后打卡时间作为额外加班调整生效日期
                                    dayAdjustRecord.setDayFirstClockRecord(dateUtil.dateToStringByFormat(userCheckDate));
                                }
                                clockString = clockString + dateUtil.dateToStringByFormat(userCheckDate) + " | ";
                                if(userCheckDate.getTime() <= onDutyCheckEnd.getTime() + (minNeglectWorkHours * 60 * 1000) && userCheckDate.getTime() >= onDutyCheckStart.getTime()){
                                    startDate = userCheckDate;
                                }

                                if(userCheckDate.getTime() >= offDutyCheckStart.getTime() - (minNeglectWorkHours * 60 * 1000) && userCheckDate.getTime() <= offDutyCheckEnd.getTime()){
                                    if(null == endDate){
                                        endDate = userCheckDate;
                                    }else if(userCheckDate.getTime() > endDate.getTime()){
                                        endDate = userCheckDate;
                                    }
                                }

                                if(userCheckDate.getTime() > onDuty.getTime() + (minNeglectWorkHours * 60 * 1000) && userCheckDate.getTime() < offDuty.getTime() - (minNeglectWorkHours * 60 * 1000)){
                                    if(null == midDate){
                                        midDate = userCheckDate;
                                    }else if(userCheckDate.getTime() > midDate.getTime() && null != startDate){ //当上班打卡不为空，中间打卡找最大值
                                        midDate = userCheckDate;
                                    }else if(userCheckDate.getTime() < midDate.getTime()){ //如果上班打卡为空，则默认中间打卡找最小值
                                        midDate = userCheckDate;
                                    }
                                }
                            }

                            //计算每日出勤
                            long hasAttendanceMills = 0L;
                            long hasAddMills = 0L;
                            if(null != startDate && null != endDate){
                                hasAttendanceMills = offDuty.getTime() - onDuty.getTime() - restTimeInShiftMills;
                            }else if(null != midDate){
                                if(null != startDate){
                                    hasAttendanceMills = midDate.getTime() - onDuty.getTime();
                                }
                                if(null != endDate){
                                    hasAttendanceMills = offDuty.getTime() - midDate.getTime();
                                }
                                if(null != restIDsInShift){
                                    JSONArray array = JSONArray.parseArray(restIDsInShift);
                                    for (Object obj : array
                                    ) {
                                        RestTimeSettings settings = restTimeSettingsMap.get(obj);
                                        Date startTime = dateUtil.getDateByPointDate(dateString.toString(), settings.getStartTime());
                                        Date endTime = dateUtil.getDateByPointDate(dateString.toString(), settings.getEndTime());

                                        if(isNight){
                                            int onDutyHour = dateUtil.getHourByDate(onDuty); //上班小时数应为前一天的晚间
                                            int onRestStartHour = dateUtil.getHourByDate(startTime); //开始休息时间的小时数
                                            //如果开始休息的小时数在上班时间小时数和23点之间或等于23点，则这段休息时间应该在夜班的开始这一天，而不是结束（跨天）这一天
                                            if(onRestStartHour > onDutyHour && onRestStartHour <= 23){
                                                startTime = dateUtil.dateAddOne(startTime, -1);
                                                endTime = dateUtil.dateAddOne(endTime, -1);
                                            }
                                        }

                                        if((midDate.getTime() <= startTime.getTime() && null != endDate) || (midDate.getTime() >= endTime.getTime() && null != startDate)){
                                            hasAttendanceMills = hasAttendanceMills - (endTime.getTime() - startTime.getTime());
                                        }
                                    }
                                }
                            }

                            //计算每日加班
                            float hasAddHours = 0F;
                            if(null != endDate && (null != startDate || null != midDate)){
                                hasAddMills = endDate.getTime() - offDuty.getTime();
                                if(null != restIDSInOverTime){
                                    JSONArray array = JSONArray.parseArray(restIDSInOverTime);
                                    for (Object obj : array
                                    ) {
                                        RestTimeSettings restTimeSettings = restTimeSettingsMap.get(obj);
                                        Date startTime = dateUtil.getDateByPointDate(dateString.toString(), restTimeSettings.getStartTime());
                                        Date endTime = dateUtil.getDateByPointDate(dateString.toString(), restTimeSettings.getEndTime());
                                        if(endDate.getTime() > startTime.getTime()){
                                            hasAddMills = hasAddMills - (endTime.getTime() - startTime.getTime());
                                        }
                                    }
                                }
                                hasAddHours = dateUtil.getHoursByMills(hasAddMills);
                                if(null != overtimeRules){
                                    float unitHour = dateUtil.getFloatWithOneBit((float) overtimeRules.getOvertimeUnit() / 60);
                                    if(hasAddHours * 60 > overtimeRules.getMaxOvertimeHours()){
                                        hasAddHours = dateUtil.getFloatWithOneBit(overtimeRules.getMaxOvertimeHours() / (float) 60);
                                    }else if(hasAddHours * 60 < overtimeRules.getMinOvertimeHours()){
                                        hasAddHours = 0F;
                                    }else{
                                        if(hasAddHours % 1 < unitHour){
                                            hasAddHours = (int) hasAddHours;
                                        }else if(hasAddHours % 1 == unitHour){
                                            //不用处理
                                        }else {
                                            hasAddHours = (int) hasAddHours + unitHour;
                                        }
                                    }
                                }
                            }

                            float hasAttendanceHours = dateUtil.getHoursByMills(hasAttendanceMills);
                            if(hasAttendanceHours % 1 < 0.5){
                                hasAttendanceHours = (int) hasAttendanceHours;
                            }else if(hasAttendanceHours % 1 == 0.5){
                                //不用处理
                            }else {
                                hasAttendanceHours = (int) hasAttendanceHours + 0.5F;
                            }

                            dayAdjustRecord.setHasAttendanceHours(hasAttendanceHours);
                            dayAdjustRecord.setHasAddHours(hasAddHours);
                        }
                        dayAdjustRecord.setClockRecords(clockString);
                        dayAdjustRecord.setGroupName(groupInfo.getAttendanceGroupName());
                    }
                    dayAdjustRecord.setContactID(cb.getContactId());
                    dayAdjustRecord.setStaffName(cb.getStaffName());
                    dayAdjustRecord.setJobNumber(cb.getStaffId());
                    float addMoreHours = 0F;
                    List<FrontLineDayAdjustRecord> dayAdjustRecords = adjustRecordMap.get(cb.getContactId());
                    if(null != dayAdjustRecords && dayAdjustRecords.size() != 0){
                        for (FrontLineDayAdjustRecord fr : dayAdjustRecords
                             ) {
                            addMoreHours = addMoreHours + fr.getAdjustHours();
                        }
                    }
                    dayAdjustRecord.setHasAddMoreHours(dateUtil.getFloatWithOneBit(addMoreHours));
                    dayAdjustRecord.setDayTotalHours(dayAdjustRecord.getHasAttendanceHours() + dayAdjustRecord.getHasAddHours() + dayAdjustRecord.getHasAddMoreHours());
                    dayAdjustRecordList.add(dayAdjustRecord);
                }
            }

            //存入结果集到返回对象
            targetMap.put("contactBasics", basics);
            targetMap.put("vacationRecords", vacationRecords);
            targetMap.put("vacationTypes", vacationTypes);
            targetMap.put("dayAdjustRecordList",dayAdjustRecordList);

            list.add(targetMap);

        }catch (Exception e){
            e.printStackTrace();
            resultEntity.setCode("F");
            resultEntity.setMsg("加载初始化信息失败");
            return resultEntity;
        }
        resultEntity.setCode("S");
        resultEntity.setMsg("Success");
        resultEntity.setDataList(list);
        return resultEntity;
    }

    /**
     * 获取钉钉打卡记录
     * @param checkClockDateFrom
     * @param checkClockDateTo
     * @return
     */
    private List<DingClockRecord> getDingClockRecords(List<ContactBasic> basics, String checkClockDateFrom, String checkClockDateTo){
        List<DingClockRecord> clockRecords = new ArrayList<>();
        if(null != basics && basics.size() != 0){
            int count = basics.size();
            List<String> userIDs = new ArrayList<>();
            for (int i = 1; i <= count; i++) {
                userIDs.add(basics.get(i - 1).getDingUserid());
                if(i == count){
                    clockRecords.addAll(dingAccessUtils.doGetDingClockRecord(userIDs, checkClockDateFrom, checkClockDateTo));
                }else if(i >= 50 && i % 50 == 0){
                    clockRecords.addAll(dingAccessUtils.doGetDingClockRecord(userIDs, checkClockDateFrom, checkClockDateTo));
                    userIDs = new ArrayList<>();
                }
            }
        }
        return clockRecords;
    }


    /**
     * 自动按天同步钉钉打卡记录了（按通讯录所有在职人员） 10800000 = 3小时  1800000 = 30分钟
     */
    @Scheduled(initialDelay = 40000, fixedDelay = 1800000)
    private void doAutoSyncDingClockRecord(){
        String token = dingAccessUtils.getAppAccessToken();
        if(token.equals("N") || token.equals("F")){
            log.info("未配置小程序认证或服务器时间不正确");
        }else {
            Date date = new Date();
            String dateStr = dateUtil.dateToString(date);
            String checkClockDateFrom = dateStr + " 00:00:00";
            String checkClockDateTo = dateStr + " 23:59:59";
            int count = 0;
            List<ContactBasic> contactBasics = iContactBasicService.selectAllContactBasicByStaffStatus(1); //员工状态，一般包括正式1、离职2
            List<DingClockRecord> dayDingClocks = this.getDingClockRecords(contactBasics, checkClockDateFrom, checkClockDateTo); //获取钉钉中这一天的全部打卡记录
            System.out.println("自动同步程序从钉钉中获取了截至现在时刻的当天打卡记录为：" + dayDingClocks.size() + " 条记录");
            if(dayDingClocks.size() != 0){
                //先获取本地当天的打卡记录
                List<DingClockRecord> localRecords = iDingClockRecordService.selectDingClockRecordByDate(dateStr);
                if(localRecords.size() != 0){ //如果本地数据库存在该日的打卡记录，则进行甄别后再插入
                    Map<String, List<DingClockRecord>> recordMapByUserId = attendanceUtil.getDingClockRecordMap(localRecords);
                    for (DingClockRecord dr : dayDingClocks
                         ) {
                        List<DingClockRecord> userDayRecords = recordMapByUserId.get(dr.getUserid());
                        if(null != userDayRecords){ //如果这个人当天存在打卡记录，就甄别
                            boolean isContain = false;
                            for (DingClockRecord re : userDayRecords
                                 ) {
                                if(dr.getUserchecktime().getTime() == re.getUserchecktime().getTime()){
                                    isContain = true;
                                }
                            }
                            if(!isContain){
                                count = count + iDingClockRecordService.insertDingClockRecord(dr);
                            }
                        }else { //如果这个人当天不存在任何打卡记录，则批量插入
                            count = count + iDingClockRecordService.insertDingClockRecord(dr);
                        }
                    }

                }else { //如果本地数据库无任何该日期的记录，则执行全部插入操作
                    count = count + iDingClockRecordService.insertDingClockRecords(dayDingClocks);
                }

            }
            logUtil.insertSystemEventLog("HRMS", date, "自动同步了 " + count + " 条差异化打卡记录", "系统");
            log.info("系统的自动同步程序在 " + date + " 自动同步了 " + count + " 条打卡记录");
        }

    }


    /**
     * 传入指定人员集合及按月份查询出的请假记录集合，返回指定人员的请假记录
     * @param contactBasics
     * @param monthVacationRecords
     * @return
     */
    private List<FrontLineVacationRecord> getVacationRecordsByContactsAndMonth(List<ContactBasic> contactBasics, List<FrontLineVacationRecord> monthVacationRecords){
        List<FrontLineVacationRecord> resultList = new ArrayList<>();
        if(null != contactBasics){
            for (ContactBasic cb : contactBasics
            ) {
                for (FrontLineVacationRecord fvr : monthVacationRecords
                ) {
                    if(cb.getContactId().equals(fvr.getContactId())){
                        resultList.add(fvr);
                    }
                }
            }
        }
        return resultList;
    }


    /**
     * 计算月度生产人员出勤汇总信息并返回给前端页面
     * @param map 需要计算的月份
     * @param request http请求
     * @return 标准返回值对象
     */
    @RequestMapping("/hrms/supervisor/doGetMonthlyReportByDateString")
    @ResponseBody
    public ResultEntity doGetMonthlyReportByDateString(@RequestBody Map map, HttpServletRequest request){
        ResultEntity resultEntity = new ResultEntity();
        List<FrontLineMonthlyReport> resultList = new ArrayList<>();
        Object opContactID = request.getAttribute("contactId");
        Object staffName = request.getAttribute("staffName");
        Date opDate = new Date();
        //System.out.println(map);
        if(null != map){
            Object dateString = map.get("dateString"); //月份信息：2020-05
            //System.out.println("即将计算的月份为：" + dateString);
            Date firstDay = dateUtil.formatStringToDate(dateString + "-01 00:00:00"); //获取本月第一天
            int maxDay = dateUtil.getMaxDayMonth(firstDay); //获取本月一共有多少天
            //Date perDay = dateUtil.dateAddOne(firstDay, -1);//获取上个月最后一天，主要用于获取该日打卡记录，用于夜班统计计算
            Date maxDate = dateUtil.formatStringToDate(dateString + "-" + maxDay + " 23:59:59"); //获取本月最后一天
            Date nextMonthFirstDay = dateUtil.dateAddOne(maxDate, 1);//获取下个月第一天，主要用于获取该日打卡记录，用于夜班统计计算
            String nextDayStr = dateUtil.getYearByDate(nextMonthFirstDay) + "-" + (dateUtil.getMonthByDate(nextMonthFirstDay) < 10 ? "0" + dateUtil.getMonthByDate(nextMonthFirstDay) : dateUtil.getMonthByDate(nextMonthFirstDay)) + "-" + (dateUtil.getDayByDate(nextMonthFirstDay) < 10 ? "0" + dateUtil.getDayByDate(nextMonthFirstDay) : dateUtil.getDayByDate(nextMonthFirstDay));
            //获取下个月第一天的打卡记录并按照ContactID形成Map
            List<DingClockRecord> nextMonthFirstDayClocks = iDingClockRecordService.selectDingClockRecordByDate(nextDayStr);
            Map<String, List<DingClockRecord>> nextMonthFirstDayClocksMap = new HashMap<>();
            if(null != nextMonthFirstDayClocks){
                nextMonthFirstDayClocksMap = attendanceUtil.getDingClockRecordMap(nextMonthFirstDayClocks);
                //System.out.println("上月最后一天的打卡记录一共：" + perDayClocks.size() + " 条");
            }else {
                //System.out.println("上月最后一天的打卡记录一共：0 条");
            }

            //获取该主管管辖范围内的人员信息
            List<ContactBasic> basics = this.getFrontContactListBySupervisor(opContactID.toString());

            //获取部门列表并形成以部门ID为Key，部门名称为值的Map
            List<ContactBasicDeptInfo> deptInfos = iContactBasicDeptInfoService.selectAllContactBasicDeptInfo();
            Map<String, String> deptListMap = new HashMap<>();
            if(null != deptInfos){
                deptListMap = basicInfoUtil.doGetDeptMap(deptInfos);
            }

            //获取月度打卡记录
            List<DingClockRecord> clockRecords = iDingClockRecordService.selectDingClockRecordByDate(dateString.toString());
            Map<String, List<DingClockRecord>> clockRecordsMap = new HashMap<>();
            if(null != clockRecords){
                clockRecordsMap = attendanceUtil.getDingClockRecordMap(clockRecords);
                //System.out.println("本月打卡记录一共有：" + clockRecords.size() + " 条");
            }else {
                //System.out.println("本月打卡记录一共有：0 条");
            }

            //获取部门或者人员的考勤组信息，加载考勤规则
            Map<String, AttendanceGroupInfo> groupInfoMap = attendanceUtil.getAttendanceGroupInfoMap(iAttendanceGroupInfoService.selectAllAttendanceGroupInfo());
            Map<String, AttendanceShiftInfo> shiftInfoMap = attendanceUtil.getAttendanceShiftInfoMap(iAttendanceShiftInfoService.selectAllAttendanceShiftInfo());
            Map<String, CheckPointInfo> checkPointInfoMap = attendanceUtil.getCheckPointInfoMap(iCheckPointInfoService.selectAllCheckPointInfo());
            Map<String, RestTimeSettings> restTimeSettingsMap = attendanceUtil.getRestTimeSettingsMap(iRestTimeSettingsService.selectAllRestTimeSettings());
            Map<String, OvertimeRules> overtimeRulesMap = attendanceUtil.getOvertimeRulesMap(iOvertimeRulesService.selectAllOvertimeRules());
            Map<String, String> groupDeptsMap = attendanceUtil.getGroupDeptMap(iAttendanceGroupDeptsService.selectAllAttendanceGroupDepts());
            Map<String, String> groupStaffsMap = attendanceUtil.getGroupStaffMap(iAttendanceGroupStaffsService.selectAllAttendanceGroupStaffs());

            //获取每日加班动态调整记录
            List<FrontLineDayAdjustRecord> adjustRecords = iFrontLineDayAdjustRecordService.selectFrontLineDayAdjustRecordByMonth(dateString.toString());
            Map<String, List<FrontLineDayAdjustRecord>> adjustRecordMap = attendanceUtil.getFrontLineDayAdjustRecordMap(adjustRecords);

            //获取当月考勤组调整记录
            List<AttendanceGroupStaffAdjustRecord> staffAdjustRecords = iAttendanceGroupStaffAdjustRecordService.selectAttendanceGroupStaffAdjustRecordByMonth(dateString.toString());
            Map<String, List<AttendanceGroupStaffAdjustRecord>> staffAdjustRecordMap = attendanceUtil.getAttendanceGroupStaffAdjustRecordMap(staffAdjustRecords);

            //获取下一个月考勤组调整记录
            List<AttendanceGroupStaffAdjustRecord> staffAdjustRecordsNextMonth = new ArrayList<>();
            try{
                staffAdjustRecordsNextMonth = iAttendanceGroupStaffAdjustRecordService.selectAttendanceGroupStaffAdjustRecordByMonth(dateUtil.getNextMonthStrByDate(firstDay));
            }catch (Exception e){
                e.printStackTrace();
            }
            Map<String, List<AttendanceGroupStaffAdjustRecord>> staffAdjustRecordMapNextMonth = new HashMap<>();
            if(staffAdjustRecordsNextMonth.size() != 0){
                staffAdjustRecordMapNextMonth = attendanceUtil.getAttendanceGroupStaffAdjustRecordMap(staffAdjustRecordsNextMonth);
            }

            //循环人员，计算月度考勤统计
            if(null != basics && basics.size() != 0){
                for (int i = 0; i < basics.size(); i++) {
                    FrontLineMonthlyReport monthlyReport = new FrontLineMonthlyReport(0F);
                    ContactBasic cb = basics.get(i);
                    //System.out.println("即将计算用户：" + cb.getStaffName() + " 的考勤数据");
                    String deptID = JSONArray.parseArray(cb.getDept()).getString(0);
                    monthlyReport.setStaffName(cb.getStaffName());
                    monthlyReport.setJobNumber(cb.getStaffId());
                    monthlyReport.setKey(i + 1);
                    monthlyReport.setDeptName(deptListMap.get(deptID) == null ? "无部门": deptListMap.get(deptID));

                    //获取这个人当月的打卡记录（此记录不包含下月第一天的打卡记录）
                    List<DingClockRecord> userClockRecords = clockRecordsMap.get(cb.getDingUserid());
                    //按打卡日期分组形成这个人的打卡记录的Map
                    Map<Integer, List<DingClockRecord>> dayUserClockRecordMap = new HashMap<>();
                    if(null != userClockRecords){
                        dayUserClockRecordMap = attendanceUtil.getDingClockRecordMapGrByDay(userClockRecords);
                        //System.out.println("本月" + cb.getStaffName()+ "一共有打卡记录：" + userClockRecords.size() + " 条");
                    }

                    //获取这个人在本月的额外加班记录，并按照日期号分组
                    List<FrontLineDayAdjustRecord> userDayAdjustRecords = adjustRecordMap.get(cb.getContactId());
                    Map<Integer, List<FrontLineDayAdjustRecord>> userDayAdjustRecordsMap = new HashMap<>();
                    if(null != userDayAdjustRecords){
                        userDayAdjustRecordsMap = attendanceUtil.getFrontLineDayAdjustRecordMapGrByDay(userDayAdjustRecords);
                    }

                    //查询考勤组异动，形成日期循环查询集合
                    List<AttendanceGroupStaffAdjustRecord> sourceUserAdjustRecords = staffAdjustRecordMap.get(cb.getContactId());
                    List<AttendanceGroupStaffAdjustRecord> userAdjustRecords = new ArrayList<>();
                    if(null != sourceUserAdjustRecords && sourceUserAdjustRecords.size() != 0){
                        for (AttendanceGroupStaffAdjustRecord agar : sourceUserAdjustRecords
                        ) {
                            if(agar.getAction() == 2){ //去除删除操作，将新增操作的记录单独筛选出来
                                userAdjustRecords.add(agar);
                            }
                        }
                        //对人员异动记录按照新增操作的生效时间进行升序排列
                        Collections.sort(userAdjustRecords, new Comparator<AttendanceGroupStaffAdjustRecord>() {
                            @Override
                            //定义一个比较器，按照生效日期升序排列
                            public int compare(AttendanceGroupStaffAdjustRecord d1, AttendanceGroupStaffAdjustRecord d2) {
                                try {
                                    Date dt1 = d1.getDateInForce();
                                    Date dt2 = d2.getDateInForce();
                                    if (dt1.getTime() > dt2.getTime()) {
                                        return 1;
                                    } else if (dt1.getTime() < dt2.getTime()) {
                                        return -1;
                                    } else {
                                        return 0;
                                    }
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                                return 0;
                            }
                        });
                    }

                    List<DateRangeEntity> dateRangeEntities = new ArrayList<>();
                    if(null != userAdjustRecords && userAdjustRecords.size() != 0){ //当月有考勤组调整的情况
                        for (int j = 0; j <= userAdjustRecords.size(); j++) {
                            if(j == 0){
                                AttendanceGroupStaffAdjustRecord record = userAdjustRecords.get(j);
                                DateRangeEntity dateRangeEntity = new DateRangeEntity();
                                dateRangeEntity.setStart(1);
                                dateRangeEntity.setEnd(dateUtil.getDayByDate(record.getDateInForce()) - 1);
                                if(null != record.getPreviousGroupId()){
                                    dateRangeEntity.setAttendanceID(record.getPreviousGroupId());
                                }
                                dateRangeEntities.add(dateRangeEntity);
                            }
                            if(j == userAdjustRecords.size()){
                                AttendanceGroupStaffAdjustRecord record = userAdjustRecords.get(j - 1);
                                DateRangeEntity dateRangeEntity = new DateRangeEntity();
                                dateRangeEntity.setStart(dateUtil.getDayByDate(record.getDateInForce()));
                                dateRangeEntity.setEnd(maxDay);
                                dateRangeEntity.setAttendanceID(record.getAttendanceGroupId());
                                dateRangeEntities.add(dateRangeEntity);
                            }
                            if(j > 0 && j < userAdjustRecords.size()){
                                AttendanceGroupStaffAdjustRecord record1 = userAdjustRecords.get(j - 1);
                                AttendanceGroupStaffAdjustRecord record2 = userAdjustRecords.get(j);
                                DateRangeEntity dateRangeEntity = new DateRangeEntity();
                                dateRangeEntity.setStart(dateUtil.getDayByDate(record1.getDateInForce()));
                                dateRangeEntity.setEnd(dateUtil.getDayByDate(record2.getDateInForce()) - 1);
                                if(null != record2.getPreviousGroupId()){
                                    dateRangeEntity.setAttendanceID(record2.getPreviousGroupId());
                                }else {
                                    dateRangeEntity.setAttendanceID(record2.getAttendanceGroupId());
                                }
                                dateRangeEntities.add(dateRangeEntity);
                            }
                        }
                    }else { //当月无考勤组调整记录的情况，但需要考虑已经生效的下个月的调整记录
                        DateRangeEntity dateRangeEntity = new DateRangeEntity();
                        dateRangeEntity.setStart(1);
                        dateRangeEntity.setEnd(maxDay);
                        if(null != groupDeptsMap.get(deptID)){
                            dateRangeEntity.setAttendanceID(groupDeptsMap.get(deptID));
                        }else if(null != groupStaffsMap.get(cb.getContactId())){
                            List<AttendanceGroupStaffAdjustRecord> nextMonthAdjustRecordList = staffAdjustRecordMapNextMonth.get(cb.getContactId());
                            if(null != nextMonthAdjustRecordList && nextMonthAdjustRecordList.size() != 0){
                                AttendanceGroupStaffAdjustRecord record = null;
                                Iterator<AttendanceGroupStaffAdjustRecord> iterator = nextMonthAdjustRecordList.iterator();
                                while (iterator.hasNext()){
                                    AttendanceGroupStaffAdjustRecord casualRecord = iterator.next();
                                    if(null == record){
                                        record = casualRecord;
                                    }else {
                                        if(record.getDateInForce().getTime() > casualRecord.getDateInForce().getTime()){
                                            record = casualRecord;
                                        }
                                    }
                                }
                                if(null != record){
                                    dateRangeEntity.setAttendanceID(record.getPreviousGroupId());
                                }
                            }else {
                                dateRangeEntity.setAttendanceID(groupStaffsMap.get(cb.getContactId()));
                            }
                        }
                        dateRangeEntities.add(dateRangeEntity);
                    }

                    //循环计算每个人每天的考勤数据并存入每个人的月度报表对象
                    for (DateRangeEntity dr : dateRangeEntities
                         ) {
                        int startDay = dr.getStart();
                        int endDay = dr.getEnd();
                        String groupID = dr.getAttendanceID();
                        if(null != groupID){ //在考勤组ID不为空的情况下，进行计算，否则数据全部设为0
                            //获取考勤信息
                            AttendanceGroupInfo attendanceGroupInfo = groupInfoMap.get(groupID);
                            AttendanceShiftInfo shiftInfo = shiftInfoMap.get(attendanceGroupInfo.getAttendanceShiftId());

                            //获取最小旷工时间
                            int minNeglectWorkHours = shiftInfo.getMinNeglectWorkHours();

                            //System.out.println(cb.getStaffName() + " 的考勤组为：" + attendanceGroupInfo.getAttendanceGroupName());

                            OvertimeRules overtimeRules = overtimeRulesMap.get(attendanceGroupInfo.getRulesId());
                            long totalRestMillsInShift = 0L;
                            String restIDsShift = shiftInfo.getRestTimeIds();
                            String restIDsOverTime = (null == overtimeRules) ? null : overtimeRules.getRestTimeIds();
                            if(null != restIDsShift){
                                totalRestMillsInShift = getTotalRestMills(restIDsShift, restTimeSettingsMap);
                            }

                            //开始分阶段循环计算
                            for (int j = startDay; j <= endDay; j++) {

                                String todayStr = dateString.toString() + "-" + (j < 10 ? "0" + j : j);

                                Date onDutyCheck = checkPointInfoMap.get(shiftInfo.getStartCheckPointId()).getStandardTime();
                                Date onDutyCheckStart = checkPointInfoMap.get(shiftInfo.getStartCheckPointId()).getStartTime();
                                Date onDutyCheckEnd = checkPointInfoMap.get(shiftInfo.getStartCheckPointId()).getEndTime();

                                Date offDutyCheck = checkPointInfoMap.get(shiftInfo.getEndCheckPointId()).getStandardTime();
                                Date offDutyCheckStart = checkPointInfoMap.get(shiftInfo.getEndCheckPointId()).getStartTime();
                                Date offDutyCheckEnd = checkPointInfoMap.get(shiftInfo.getEndCheckPointId()).getEndTime();

                                onDutyCheck = dateUtil.getDateByPointDate(todayStr, onDutyCheck);
                                onDutyCheckStart = dateUtil.getDateByPointDate(todayStr, onDutyCheckStart);
                                onDutyCheckEnd = dateUtil.getDateByPointDate(todayStr, onDutyCheckEnd);
                                //System.out.println("上班打卡时间和范围分别是：" + onDutyCheck + " / " + onDutyCheckStart + " / " + onDutyCheckEnd);

                                offDutyCheck = dateUtil.getDateByPointDate(todayStr, offDutyCheck);
                                offDutyCheckStart = dateUtil.getDateByPointDate(todayStr, offDutyCheckStart);
                                offDutyCheckEnd = dateUtil.getDateByPointDate(todayStr, offDutyCheckEnd);
                                //System.out.println("下班打卡时间和范围分别是：" + offDutyCheck + " / " + offDutyCheckStart + " / " + offDutyCheckEnd);

                                boolean isNightShift = false;
                                if(onDutyCheck.getTime() > offDutyCheck.getTime()){ //夜班的取值变动（向后一天取值）
                                    //onDutyCheck = dateUtil.dateAddOne(onDutyCheck, -1);
                                    //onDutyCheckStart = dateUtil.dateAddOne(onDutyCheckStart, -1);
                                    //onDutyCheckEnd = dateUtil.dateAddOne(onDutyCheckEnd, -1);

                                    offDutyCheck = dateUtil.dateAddOne(offDutyCheck, 1);
                                    offDutyCheckStart = dateUtil.dateAddOne(offDutyCheckStart, 1);
                                    offDutyCheckEnd = dateUtil.dateAddOne(offDutyCheckEnd, 1);

                                    isNightShift = true;
                                    //System.out.println(cb.getStaffName() + " 属于夜班人员");
                                }else {
                                    //System.out.println(cb.getStaffName() + " 属于白班人员");
                                }

                                //获取员工这一天的打卡记录并与考勤及加班规则做比较
                                Date startCheck = null;
                                Date midCheck = null;
                                Date endCheck = null;
                                
                                List<DingClockRecord> dayClocks = dayUserClockRecordMap.get(j);
                                if(j == maxDay && isNightShift){ //如果是本月最后一天，则将下月第一天上夜班的人员打卡信息添加到本月最后一天中
                                    if(null != dayClocks && null != nextMonthFirstDayClocksMap.get(cb.getDingUserid())){
                                        dayClocks.addAll(nextMonthFirstDayClocksMap.get(cb.getDingUserid()));
                                    }
                                }else if(isNightShift){
                                    if(null != dayClocks && null != dayUserClockRecordMap.get(j + 1)){
                                        dayClocks.addAll(dayUserClockRecordMap.get(j + 1));
                                    }
                                }
                                if(null != dayClocks && dayClocks.size() != 0){
                                    for (DingClockRecord record : dayClocks
                                         ) {
                                        Date dayCheck = record.getUserchecktime();
                                        if(dayCheck.getTime() >= onDutyCheckStart.getTime() && dayCheck.getTime() <= onDutyCheckEnd.getTime() + minNeglectWorkHours * 60 * 1000){
                                            startCheck = dayCheck; //存在正常打卡
                                        }
                                        if(dayCheck.getTime() > onDutyCheck.getTime() + minNeglectWorkHours * 60 * 1000 && dayCheck.getTime() < offDutyCheck.getTime() - minNeglectWorkHours * 60 * 1000){
                                            if(null == midCheck){ //存在上班过程中打卡
                                                midCheck = dayCheck;
                                            }else if(dayCheck.getTime() < midCheck.getTime()){
                                                midCheck = dayCheck;
                                            }
                                        }
                                        if(dayCheck.getTime() >= offDutyCheckStart.getTime() - minNeglectWorkHours * 60 * 1000 && dayCheck.getTime() <= offDutyCheckEnd.getTime()){
                                            if(null == endCheck){
                                                endCheck = dayCheck;
                                            }else if(dayCheck.getTime() > endCheck.getTime()){
                                                endCheck = dayCheck;
                                            }
                                        }
                                    }
                                }


                                long attendanceMills = 0L;
                                if(null != startCheck && null != endCheck){
                                    attendanceMills = offDutyCheck.getTime() - onDutyCheck.getTime() - totalRestMillsInShift;
                                }else if(null != midCheck){
                                    if(null != startCheck){
                                        attendanceMills = midCheck.getTime() - onDutyCheck.getTime();
                                    }
                                    if(null != endCheck){
                                        attendanceMills = offDutyCheck.getTime() - midCheck.getTime();
                                    }
                                    if(null != restIDsShift){
                                        JSONArray array = JSONArray.parseArray(restIDsShift);
                                        for (Object obj : array
                                        ) {
                                            RestTimeSettings settings = restTimeSettingsMap.get(obj);
                                            Date restStartTime = dateUtil.getDateByPointDate(todayStr, settings.getStartTime());
                                            Date restEndTime = dateUtil.getDateByPointDate(todayStr, settings.getEndTime());

                                            if(isNightShift){
                                                int onDutyHour = dateUtil.getHourByDate(onDutyCheck);
                                                int onRestStartHour = dateUtil.getHourByDate(restStartTime);
                                                if(onRestStartHour > onDutyHour && onRestStartHour <= 23){
                                                    restStartTime = dateUtil.dateAddOne(restStartTime, -1);
                                                    restEndTime = dateUtil.dateAddOne(restEndTime, -1);
                                                }
                                            }

                                            if((midCheck.getTime() <= restStartTime.getTime() && null != endCheck) || (midCheck.getTime() >= restEndTime.getTime() && null != startCheck)){
                                                attendanceMills = attendanceMills - (settings.getEndTime().getTime() - settings.getStartTime().getTime());
                                            }
                                        }
                                    }
                                }

                                long addMills = 0L;
                                float addHours = 0F;
                                if(null != endCheck && (null != startCheck || null != midCheck)){
                                    addMills = endCheck.getTime() - offDutyCheck.getTime();
                                    long totalRestTime = 0L; //范围内的总休息时段累加的毫秒数
                                    if(null != restIDsOverTime){
                                        JSONArray array = JSONArray.parseArray(restIDsOverTime);
                                        for (Object obj : array
                                        ) {
                                            RestTimeSettings settings = restTimeSettingsMap.get(obj);
                                            Date restStartTime = dateUtil.getDateByPointDate(todayStr, settings.getStartTime());
                                            Date restEndTime = dateUtil.getDateByPointDate(todayStr, settings.getEndTime());
                                            if(endCheck.getTime() > restStartTime.getTime()){
                                                totalRestTime = totalRestTime + (restEndTime.getTime() - restStartTime.getTime());
                                            }
                                        }
                                    }
                                    if(totalRestTime != 0){
                                        addMills = addMills - totalRestTime;
                                    }
                                    addHours = dateUtil.getHoursByMills(addMills);
                                    if(null != overtimeRules){
                                        float unitHour = dateUtil.getFloatWithOneBit((float) overtimeRules.getOvertimeUnit() / 60);
                                        if(addHours * 60 > overtimeRules.getMaxOvertimeHours()){
                                            addHours = dateUtil.getFloatWithOneBit(overtimeRules.getMaxOvertimeHours() / (float) 60);
                                        }else if(addHours * 60 < overtimeRules.getMinOvertimeHours()){
                                            addHours = 0F;
                                        }else {
                                            if(addHours % 1 < unitHour){
                                                addHours = (int) addHours;
                                            }else if(addHours % 1 == unitHour){
                                                //不用处理
                                            }else {
                                                addHours = (int) addHours + unitHour;
                                            }
                                        }
                                    }
                                }

                                float attendanceHours = dateUtil.getHoursByMills(attendanceMills);
                                if(attendanceHours % 1 < 0.5){
                                    attendanceHours = (int) attendanceHours;
                                }else if(attendanceHours % 1 == 0.5){
                                    //不用处理
                                }else {
                                    attendanceHours = (int) attendanceHours + 0.5F;
                                }


                                //查询这一天这个人是否存在额外加班调整，有且只会有一条记录
                                float exAddHours = 0F;
                                List<FrontLineDayAdjustRecord> frontLineDayAdjustRecords = userDayAdjustRecordsMap.get(j);
                                if(null != frontLineDayAdjustRecords){
                                    exAddHours = frontLineDayAdjustRecords.get(0).getAdjustHours();
                                }

                                String result = attendanceHours + "-" + addHours + "-" + exAddHours;

                                switch (j){
                                    case 1:
                                        monthlyReport.setM01(result);
                                        break;
                                    case 2:
                                        monthlyReport.setM02(result);
                                        break;
                                    case 3:
                                        monthlyReport.setM03(result);
                                        break;
                                    case 4:
                                        monthlyReport.setM04(result);
                                        break;
                                    case 5:
                                        monthlyReport.setM05(result);
                                        break;
                                    case 6:
                                        monthlyReport.setM06(result);
                                        break;
                                    case 7:
                                        monthlyReport.setM07(result);
                                        break;
                                    case 8:
                                        monthlyReport.setM08(result);
                                        break;
                                    case 9:
                                        monthlyReport.setM09(result);
                                        break;
                                    case 10:
                                        monthlyReport.setM10(result);
                                        break;
                                    case 11:
                                        monthlyReport.setM11(result);
                                        break;
                                    case 12:
                                        monthlyReport.setM12(result);
                                        break;
                                    case 13:
                                        monthlyReport.setM13(result);
                                        break;
                                    case 14:
                                        monthlyReport.setM14(result);
                                        break;
                                    case 15:
                                        monthlyReport.setM15(result);
                                        break;
                                    case 16:
                                        monthlyReport.setM16(result);
                                        break;
                                    case 17:
                                        monthlyReport.setM17(result);
                                        break;
                                    case 18:
                                        monthlyReport.setM18(result);
                                        break;
                                    case 19:
                                        monthlyReport.setM19(result);
                                        break;
                                    case 20:
                                        monthlyReport.setM20(result);
                                        break;
                                    case 21:
                                        monthlyReport.setM21(result);
                                        break;
                                    case 22:
                                        monthlyReport.setM22(result);
                                        break;
                                    case 23:
                                        monthlyReport.setM23(result);
                                        break;
                                    case 24:
                                        monthlyReport.setM24(result);
                                        break;
                                    case 25:
                                        monthlyReport.setM25(result);
                                        break;
                                    case 26:
                                        monthlyReport.setM26(result);
                                        break;
                                    case 27:
                                        monthlyReport.setM27(result);
                                        break;
                                    case 28:
                                        monthlyReport.setM28(result);
                                        break;
                                    case 29:
                                        monthlyReport.setM29(result);
                                        break;
                                    case 30:
                                        monthlyReport.setM30(result);
                                        break;
                                    case 31:
                                        monthlyReport.setM31(result);
                                        break;
                                }
                                monthlyReport.setTotalHours(monthlyReport.getTotalHours() + dateUtil.getFloatWithOneBit(attendanceHours) + addHours + exAddHours);
                            }
                        }else {
                            //System.out.println(cb.getStaffName() + " 无考勤组信息");
                        }
                    }
                    //System.out.println("即将计算用户：" + cb.getStaffName() + " 的考勤数据计算结束");
                    //向结果集存入每个人的计算结果
                    resultList.add(monthlyReport);
                }
            }
            resultEntity.setCode("S");
            resultEntity.setMsg("Success");
            resultEntity.setDataList(resultList);
            return resultEntity;
        }else {
            resultEntity.setCode("F");
            resultEntity.setMsg("参数传入错误");
            return resultEntity;
        }
    }


    /**
     * 传入休息时段ID，返回休息时段累计小时数
     * @param restID
     * @param restTimeSettingsMap
     * @return
     */
    private float getTotalRestHours(String restID, Map<String, RestTimeSettings> restTimeSettingsMap){
        float totalHours = 0F;
        JSONArray array = JSONArray.parseArray(restID);
        for (Object obj : array
        ) {
            RestTimeSettings restTimeSettings = restTimeSettingsMap.get(obj);
            totalHours = totalHours + dateUtil.getTimeDifferenceByTime(restTimeSettings.getEndTime(), restTimeSettings.getStartTime());
        }
        return totalHours;
    }

    /**
     * 传入休息时段ID，返回休息时段累计毫秒数
     * @param restID
     * @param restTimeSettingsMap
     * @return
     */
    private long getTotalRestMills(String restID, Map<String, RestTimeSettings> restTimeSettingsMap){
        long totalMills = 0L;
        JSONArray array = JSONArray.parseArray(restID);
        for (Object obj : array
        ) {
            RestTimeSettings restTimeSettings = restTimeSettingsMap.get(obj);
            totalMills = totalMills + (dateUtil.getDateByPointDate("2022-05-01", restTimeSettings.getEndTime()).getTime() - dateUtil.getDateByPointDate("2022-05-01", restTimeSettings.getStartTime()).getTime());
        }
        return totalMills;
    }


    /**
     * 获取一线主管管辖范围内的人员名单
     * @param contactID
     * @return
     */
    private List<ContactBasic> getFrontContactListBySupervisor(String contactID){
        List<ContactBasic> basics = new ArrayList<>();
        try{
            List<ContactBasic> contactBasics = iContactBasicService.selectAllContactBasicByStaffStatus(1);
            List<ContactBasicDeptInfo> deptInfos = iContactBasicDeptInfoService.selectAllContactBasicDeptInfo();
            FrontLineSupervisorDepts supervisorDept = iFrontLineSupervisorDeptsService.selectFrontLineSupervisorDeptsBySID(contactID);
            List<Long> depts = new ArrayList<>();
            if(null != supervisorDept){
                depts = JSONArray.parseArray(supervisorDept.getDeptIds(), Long.class);
            }
            basics = basicInfoUtil.doGetAllContactsByDeptIDs(contactBasics, deptInfos, depts);
        }catch (Exception e){
            e.printStackTrace();
        }
        return basics;
    }


    /**
     * 传入月份，查询该月所有一线人员的休假记录
     * @param map 月份集合
     * @param request http请求
     * @return 标准返回值对象
     */
    @RequestMapping("/hrms/supervisor/doGetFrontLineVacationRecords")
    @ResponseBody
    public ResultEntity doGetFrontLineVacationRecords(@RequestBody Map map, HttpServletRequest request){
        ResultEntity resultEntity = new ResultEntity();
        Date cTime = new Date();
        Object staffName = request.getAttribute("staffName");
        //System.out.println(map);
        if(null != map){
            Object dateString = map.get("dateString");
            if(null != dateString){
                List<FrontLineVacationRecord> records = iFrontLineVacationRecordService.selectFrontLineVacationRecordByMonth(dateString.toString());
                resultEntity.setCode("S");
                resultEntity.setMsg("Success");
                resultEntity.setDataList(records);
                return resultEntity;
            }
        }else {
            resultEntity.setCode("F");
            resultEntity.setMsg("参数传递错误");
            return resultEntity;
        }
        resultEntity.setCode("S");
        resultEntity.setMsg("Success");
        return resultEntity;
    }



    /**
     * 该方法将接收前端传来的参数，向数据库插入一个一线员工的请假记录
     * @param map 前端传入的数据
     * @param request http请求
     * @return 标准返回值对象
     */
    @RequestMapping("/hrms/supervisor/doInsertFrontLineVacationRecord")
    @ResponseBody
    public ResultEntity doInsertFrontLineVacationRecord(@RequestBody Map map, HttpServletRequest request){
        ResultEntity resultEntity = new ResultEntity();
        Date cTime = new Date();
        Object opContactID = request.getAttribute("contactId");
        Object staffName = request.getAttribute("staffName");
        //System.out.println(map);
        if(null != map){
            Object contactID = map.get("contactId");
            Object rangeTime = map.get("rangeTime");
            Object intSet = map.get("intSet");
            Object type = map.get("type");
            if(null != contactID && null != rangeTime && null != intSet && null != type){
                JSONArray dateArray = JSONArray.parseArray(JSON.toJSONString(rangeTime));
                Date start = null;
                Date end = null;
                if(null != dateArray){
                    try{
                        start = dateUtil.formatDateByString(dateArray.getString(0));
                        end = dateUtil.formatDateByString(dateArray.getString(1));
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
                if(null != start && null != end){
                    //判断请假日期是否已经存在
                    List<FrontLineVacationRecord> startInList = iFrontLineVacationRecordService.selectFrontLineVacationRecordByDateForOneContact(dateUtil.dateToString(start));
                    List<FrontLineVacationRecord> endList = iFrontLineVacationRecordService.selectFrontLineVacationRecordByDateForOneContact(dateUtil.dateToString(end));
                    startInList.addAll(endList);

                    if(startInList.size() != 0){
                        for (FrontLineVacationRecord flvr : startInList
                             ) {
                            if(contactID.toString().equals(flvr.getContactId())){
                                Date recordStart = flvr.getStartTime();
                                Date recordEnd = flvr.getEndTime();
                                if(start.getTime() >= recordStart.getTime() && start.getTime() <= recordEnd.getTime()){ //新的请假开始时间在请假记录之间
                                    resultEntity.setCode("F");
                                    resultEntity.setMsg("请假时间重叠");
                                    return resultEntity;
                                }
                                if(end.getTime() >= recordStart.getTime() && end.getTime() <= recordEnd.getTime()){ //新的请假结束时间在请假记录之间
                                    resultEntity.setCode("F");
                                    resultEntity.setMsg("请假时间重叠");
                                    return resultEntity;
                                }
                                if(start.getTime() <= recordStart.getTime() && end.getTime() >= recordEnd.getTime()){ //新的请假开始时间包含了请假记录区间
                                    resultEntity.setCode("F");
                                    resultEntity.setMsg("请假时间重叠");
                                    return resultEntity;
                                }
                            }
                        }
                    }


                    //判断用户传入的时间是否跨月（跨年）
                    int yearStart = dateUtil.getYearByDate(start);
                    int yearEnd = dateUtil.getYearByDate(end);
                    List<DateInMonthEntity> rangeEntities = new ArrayList<>();
                    if(yearEnd - yearStart > 1){
                        resultEntity.setCode("F");
                        resultEntity.setMsg("不允许跨两年请假");
                        return resultEntity;
                    }else {
                        if(yearEnd - yearStart == 1){ //跨一年请假的情况
                            int monthStart = dateUtil.getMonthByDate(start);
                            for (int i = monthStart; i <= 12; i++) {
                                String monthStr = yearStart + "-" + ((i < 10) ? "0" + i : i);
                                DateInMonthEntity dr = new DateInMonthEntity();
                                if(i == monthStart){
                                    dr.setDateStart(start);
                                    dr.setDateEnd(dateUtil.getLastDayCalendarByMonth(monthStr));
                                }else {
                                    dr.setDateStart(dateUtil.getFirstDayCalendarByMonth(monthStr));
                                    dr.setDateEnd(dateUtil.getLastDayCalendarByMonth(monthStr));
                                }
                                rangeEntities.add(dr);
                            }
                            int monthEnd = dateUtil.getMonthByDate(end);
                            for (int i = 1; i <= monthEnd; i++) {
                                String monthStr = yearEnd + "-" + ((i < 10) ? "0" + i : i);
                                DateInMonthEntity dr = new DateInMonthEntity();
                                if(i == monthEnd){
                                    dr.setDateStart(dateUtil.getFirstDayCalendarByMonth(monthStr));
                                    dr.setDateEnd(end);
                                }else {
                                    dr.setDateStart(dateUtil.getFirstDayCalendarByMonth(monthStr));
                                    dr.setDateEnd(dateUtil.getLastDayCalendarByMonth(monthStr));
                                }
                                rangeEntities.add(dr);
                            }
                        }else { //无跨年的情况
                            int monthStart = dateUtil.getMonthByDate(start);
                            int monthEnd = dateUtil.getMonthByDate(end);
                            if(monthEnd - monthStart >= 1){
                                for (int i = monthStart; i <= monthEnd; i++) {
                                    String monthStr = yearStart + "-" + ((i < 10) ? "0" + i : i);
                                    DateInMonthEntity dr = new DateInMonthEntity();
                                    if(i == monthStart){
                                        dr.setDateStart(start);
                                        dr.setDateEnd(dateUtil.getLastDayCalendarByMonth(monthStr));
                                    }else if(i == monthEnd){
                                        dr.setDateStart(dateUtil.getFirstDayCalendarByMonth(monthStr));
                                        dr.setDateEnd(end);
                                    }else {
                                        dr.setDateStart(dateUtil.getFirstDayCalendarByMonth(monthStr));
                                        dr.setDateEnd(dateUtil.getLastDayCalendarByMonth(monthStr));
                                    }
                                    rangeEntities.add(dr);
                                }
                            }else {
                                DateInMonthEntity dr = new DateInMonthEntity();
                                dr.setDateStart(start);
                                dr.setDateEnd(end);
                                rangeEntities.add(dr);
                            }
                        }
                    }
                    //循环rangeEntities，计算总休假时间
                    float count = 0F;
                    for (DateInMonthEntity d : rangeEntities
                         ) {
                        Date startDate = d.getDateStart();
                        Date endDate = d.getDateEnd();
                        int year = dateUtil.getYearByDate(startDate);
                        int month = dateUtil.getMonthByDate(startDate);
                        String monthStr = year + "-" + (month < 10 ? "0" + month : month);
                        List<Integer> weekends = dateUtil.getWeekendListByMonth(dateUtil.getCalendarByMonth(monthStr));
                        List<HolidayRecord> holidayRecords = iHolidayRecordService.selectHolidayRecordByMonth(monthStr);
                        Map<Integer, HolidayRecord> holidayRecordMap = attendanceUtil.getHolidayRecordMap(holidayRecords);
                        List<Integer> finalRestDays = new ArrayList<>();
                        for (int i = 1; i <= 31; i++) {
                            HolidayRecord hr = holidayRecordMap.get(i); //休假类型，1表示假日，2表示工作日调休，3表示周末调休
                            if(null != hr){
                                if(hr.getHolidayType() == 1 || hr.getHolidayType() == 3){
                                    finalRestDays.add(i);
                                }
                                if(hr.getHolidayType() == 3 && weekends.contains(i)){
                                    Iterator iterator = weekends.iterator();
                                    while (iterator.hasNext()){
                                        Integer week = (Integer) iterator.next();
                                        if(week == i){
                                            iterator.remove();
                                        }
                                    }
                                }
                            }else {
                                if(weekends.contains(i)){
                                    finalRestDays.add(i);
                                }
                            }
                        }
                        //System.out.println(finalRestDays);
                        count = count + this.doGetLeaveHours(startDate, endDate, contactID.toString(), Integer.parseInt(intSet.toString()), finalRestDays);
                    }
                    //System.out.println(count);
                    FrontLineVacationRecord f = new FrontLineVacationRecord();
                    f.setcTime(cTime);
                    f.setFid(UUIDUtil.createUUID());
                    f.setContactId(contactID.toString());
                    f.setStartTime(start);
                    f.setEndTime(end);
                    f.setRoundingMethod(Integer.parseInt(intSet.toString()));
                    f.setVacationTypeCode(type.toString());
                    f.setTotalHours(count);
                    f.setHasPrinted(0);
                    f.setOpContactId(opContactID.toString());
                    int i = iFrontLineVacationRecordService.insertFrontLineVacationRecord(f);
                    if(i != 0){
                        ContactBasic contactBasic = iContactBasicService.selectContactBasicByContactID(contactID.toString());
                        logUtil.insertSystemEventLog(staffName.toString(), cTime, "创建了一条请假记录，请假人为: " + contactBasic.getStaffName() + "，开始时间为: " + start + "，请假结束时间为: " + end, "考勤");
                        resultEntity.setCode("S");
                        resultEntity.setMsg("Success");
                        return resultEntity;
                    }
                }else {
                    resultEntity.setCode("F");
                    resultEntity.setMsg("传入参数错误");
                    return resultEntity;
                }
            }else{
                resultEntity.setCode("F");
                resultEntity.setMsg("传入参数错误");
                return resultEntity;
            }
        }else{
            resultEntity.setCode("F");
            resultEntity.setMsg("传入参数错误");
            return resultEntity;
        }
        resultEntity.setCode("F");
        resultEntity.setMsg("Fail");
        return resultEntity;
    }


    /**
     * 该方法将接收前端传来的参数，向数据库删除一个请假记录
     * @param map 需要删除的数据
     * @param request http请求
     * @return 标准返回值对象
     */
    @RequestMapping("/hrms/supervisor/doDeleteFrontLineVacationRecord")
    @ResponseBody
    public ResultEntity doDeleteFrontLineVacationRecord(@RequestBody Map map, HttpServletRequest request){
        ResultEntity resultEntity = new ResultEntity();
        Date opDate = new Date();
        Object staffName = request.getAttribute("staffName");
        Object fid = map.get("fid");
        if(null != fid){
            FrontLineVacationRecord record = iFrontLineVacationRecordService.selectFrontLineVacationRecordByFID(fid.toString());
            if(null != record){
                int i = iFrontLineVacationRecordService.deleteFrontLineVacationRecord(record);
                if(i != 0){
                    ContactBasic contactBasic = iContactBasicService.selectContactBasicByContactID(record.getContactId());
                    logUtil.insertSystemEventLog(staffName.toString(), opDate, "删除了一条" + contactBasic.getStaffName() + "的请假记录", "考勤");
                    resultEntity.setCode("S");
                    resultEntity.setMsg("Success");
                    return resultEntity;
                }
            }
        }else {
            resultEntity.setCode("F");
            resultEntity.setMsg("传入参数有误");
            return resultEntity;
        }
        resultEntity.setCode("F");
        resultEntity.setMsg("Fail");
        return resultEntity;
    }


    /**
     * 传入请假起止时间和通讯里ID，查询考勤组考勤设置并计算出合理的请假时间，若存在跨月或者跨年，需循环计算
     * @param start 当月开始日期
     * @param end 当月结束日期
     * @param contactID
     * @param integerList 周末与节假日数组
     * @return
     */
    private float doGetLeaveHours(Date start, Date end, String contactID, int intSet, List<Integer> integerList){
        float leaveHours = 0F;
        String startDateString = dateUtil.dateToString(start); //获取开始请假这一天的Date String
        String endDateString = dateUtil.dateToString(end); //获取结束休假这一天的Date String
        ContactBasic contactBasic = iContactBasicService.selectContactBasicByContactID(contactID);
        JSONArray deptIDs = JSONArray.parseArray(contactBasic.getDept());
        String deptID = deptIDs.getString(0);
        AttendanceGroupDepts attendanceGroupDepts = (null != deptID) ? iAttendanceGroupDeptsService.selectAttendanceGroupDeptsByDeptID(deptID) : null;
        AttendanceGroupStaffs attendanceGroupStaffs = iAttendanceGroupStaffsService.selectOneAttendanceGroupStaffsByContactID(contactID);
        if(null != attendanceGroupDepts || null != attendanceGroupStaffs){
            AttendanceShiftInfo shiftInfo;
            if(null != attendanceGroupDepts){
                shiftInfo = iAttendanceShiftInfoService.selectOneAttendanceShiftInfoByShiftID(iAttendanceGroupInfoService.selectOneAttendanceGroupInfoByAgId(attendanceGroupDepts.getAttendanceGroupId()).getAttendanceShiftId());
            }else {
                shiftInfo = iAttendanceShiftInfoService.selectOneAttendanceShiftInfoByShiftID(iAttendanceGroupInfoService.selectOneAttendanceGroupInfoByAgId(attendanceGroupStaffs.getAttendanceGroupId()).getAttendanceShiftId());
            }
            Date onDutyCheck = dateUtil.getDateByPointDate(startDateString, iCheckPointInfoService.selectOneCheckPointInfoByCheckPointID(shiftInfo.getStartCheckPointId()).getStandardTime());
            Date offDutyCheck = dateUtil.getDateByPointDate(endDateString, iCheckPointInfoService.selectOneCheckPointInfoByCheckPointID(shiftInfo.getEndCheckPointId()).getStandardTime());
            int dayStart = dateUtil.getDayByDate(start);
            int dayEnd = dateUtil.getDayByDate(end);
            boolean isNightShift = false;
            if(dateUtil.getDateByPointDate(startDateString, offDutyCheck).getTime() < onDutyCheck.getTime()){ //当上下班时间在同一日期时，如果下班时间小于上班时间，则是夜班
                isNightShift = true;
                //System.out.println("是跨夜班考勤");
            }
            String restTimeIDs = shiftInfo.getRestTimeIds();
            Map<String, RestTimeSettings> restTimeSettingsMap = attendanceUtil.getRestTimeSettingsMap(iRestTimeSettingsService.selectAllRestTimeSettings());

            Date startDate = null; //用于计算的请假开始具体时间取值
            Date endDate = null; //用于计算的请假结束具体时间取值
            Date lastStartDate = null; //用于缓存跨天的最后一天开始时间
            Date firstEndDate = null; //用于缓存跨天的第一天结束时间
            int diff = 0; //隔天的情况需要考虑具体跨了几天
            if(dateUtil.isSameDay(start, end) && !isNightShift){ //当天内请假
                if(start.getTime() < onDutyCheck.getTime() && end.getTime() > offDutyCheck.getTime()){
                    startDate = onDutyCheck;
                    endDate = offDutyCheck;
                }
                if(start.getTime() >= onDutyCheck.getTime() && end.getTime() > offDutyCheck.getTime()){
                    startDate = start;
                    endDate = offDutyCheck;
                }
                if(start.getTime() < onDutyCheck.getTime() && end.getTime() <= offDutyCheck.getTime()){
                    startDate = onDutyCheck;
                    endDate = end;
                }
                if(start.getTime() >= onDutyCheck.getTime() && end.getTime() <= offDutyCheck.getTime()){
                    startDate = start;
                    endDate = end;
                }
                leaveHours = doCutRestTime(startDate, endDate, restTimeIDs, restTimeSettingsMap);
            }else {
                if(isNightShift){ //存在夜班
                    if(dateUtil.isSameDay(start, end)){ //存在夜班，且请假的开始和结束时间在同一天
                        Date checkDate;
                        for (int i = 0; i < 2; i++) {
                            if(i == 0){
                                checkDate = start;
                            }else {
                                checkDate = end;
                            }
                            if((checkDate.getTime() >= dateUtil.formatStringToDate(startDateString + " 00:00:00").getTime() && checkDate.getTime() < offDutyCheck.getTime()) ||
                                    ((checkDate.getTime() >= onDutyCheck.getTime() && checkDate.getTime() < dateUtil.formatStringToDate(startDateString + " 23:59:59").getTime()))
                            ){
                                if(i == 0){
                                    startDate = checkDate;
                                }else {
                                    endDate = checkDate;
                                }

                            }else if(checkDate.getTime() > offDutyCheck.getTime() && checkDate.getTime() < onDutyCheck.getTime()){
                                if(i == 0){
                                    startDate = onDutyCheck;
                                }else {
                                    endDate = offDutyCheck;
                                }
                            }
                        }
                        if(null != startDate && null != endDate){
                            leaveHours = doCutRestTime(startDate, endDate, restTimeIDs, restTimeSettingsMap);
                        }
                    }else { //存在夜班，且请假开始和结束日期跨天的情况，可能跨一天及一天以上，但不会存在跨月
                        float firstDayLeaveHours = 0F;
                        float lastDayLeaveHours = 0F;

                        if(start.getTime() >= dateUtil.formatStringToDate(startDateString + " 00:00:00").getTime() && start.getTime() < dateUtil.getDateByPointDate(startDateString, offDutyCheck).getTime()){
                            firstDayLeaveHours = doCutRestTime(start, dateUtil.getDateByPointDate(startDateString, offDutyCheck), restTimeIDs, restTimeSettingsMap) + doCutRestTime(onDutyCheck, dateUtil.formatStringToDate(startDateString + " 23:59:59"), restTimeIDs, restTimeSettingsMap);
                            //firstDayLeaveHours = dateUtil.getTimeDifference(dateUtil.getDateByPointDate(startDateString, offDutyCheck), start) + dateUtil.getTimeDifference(dateUtil.formatStringToDate(startDateString + " 23:59:59"), onDutyCheck);
                        }else if(start.getTime() >= dateUtil.getDateByPointDate(startDateString, offDutyCheck).getTime() && start.getTime() <= onDutyCheck.getTime()){
                            firstDayLeaveHours = doCutRestTime(onDutyCheck, dateUtil.formatStringToDate(startDateString + " 23:59:59"), restTimeIDs, restTimeSettingsMap);
                            //firstDayLeaveHours = dateUtil.getTimeDifference(dateUtil.formatStringToDate(startDateString + " 23:59:59"), onDutyCheck);
                        }else {
                            firstDayLeaveHours = doCutRestTime(start, dateUtil.formatStringToDate(startDateString + " 23:59:59"), restTimeIDs, restTimeSettingsMap);
                            //firstDayLeaveHours = dateUtil.getTimeDifference(dateUtil.formatStringToDate(startDateString + " 23:59:59"), start);
                        }

                        if(end.getTime() >= dateUtil.formatStringToDate(endDateString + " 00:00:00").getTime() && end.getTime() < offDutyCheck.getTime()){
                            lastDayLeaveHours = doCutRestTime(dateUtil.formatStringToDate(endDateString + " 00:00:00"), end, restTimeIDs, restTimeSettingsMap);
                            //lastDayLeaveHours = dateUtil.getTimeDifference(end, dateUtil.formatStringToDate(endDateString + " 00:00:00"));
                        }else if(end.getTime() >= offDutyCheck.getTime() && end.getTime() < dateUtil.getDateByPointDate(endDateString, onDutyCheck).getTime()){
                            lastDayLeaveHours = doCutRestTime(dateUtil.formatStringToDate(endDateString + " 00:00:00"), offDutyCheck, restTimeIDs, restTimeSettingsMap);
                            //lastDayLeaveHours = dateUtil.getTimeDifference(offDutyCheck, dateUtil.formatStringToDate(endDateString + " 00:00:00"));
                        }else {
                            lastDayLeaveHours = doCutRestTime(dateUtil.getDateByPointDate(endDateString, onDutyCheck), end, restTimeIDs, restTimeSettingsMap) + doCutRestTime(dateUtil.formatStringToDate(endDateString + " 00:00:00"), offDutyCheck, restTimeIDs, restTimeSettingsMap);
                            //lastDayLeaveHours = dateUtil.getTimeDifference(end, dateUtil.getDateByPointDate(endDateString, onDutyCheck)) + dateUtil.getTimeDifference(offDutyCheck, dateUtil.formatStringToDate(endDateString + " 00:00:00"));
                        }


                        for (int i = dayStart + 1; i < dayEnd ; i++) {
                            if(!integerList.contains(i)){
                                diff = diff + 1;
                            }
                        }
                        leaveHours = firstDayLeaveHours + lastDayLeaveHours + diff * shiftInfo.getAutoDayworkHours();
                    }
                }else { //白班的跨天计算
                    if(start.getTime() < onDutyCheck.getTime()){
                        startDate = onDutyCheck;
                    }else if(start.getTime() <= dateUtil.getDateByPointDate(startDateString, offDutyCheck).getTime()){
                        startDate = start;
                    }

                    firstEndDate = dateUtil.getDateByPointDate(startDateString, offDutyCheck);
                    lastStartDate = dateUtil.getDateByPointDate(endDateString, onDutyCheck);

                    if(end.getTime() > offDutyCheck.getTime()){
                        endDate = offDutyCheck;
                    }else if(end.getTime() >= dateUtil.getDateByPointDate(endDateString, iCheckPointInfoService.selectOneCheckPointInfoByCheckPointID(shiftInfo.getStartCheckPointId()).getStandardTime()).getTime()){
                        endDate = end;
                    }

                    for (int i = dayStart + 1; i < dayEnd; i++) { //start和end的时间一定是同月的，在调用本函数之前，主函数已经做过处理
                        if(!integerList.contains(i)){
                            diff = diff + 1;
                        }
                    }

                    float firstDayLeaveHours = doCutRestTime(startDate, firstEndDate, restTimeIDs, restTimeSettingsMap);
                    float lastDayLeaveHours = doCutRestTime(lastStartDate, endDate, restTimeIDs, restTimeSettingsMap);
                    leaveHours = firstDayLeaveHours + lastDayLeaveHours + diff * shiftInfo.getAutoDayworkHours();
                }
            }
        }else {
            System.out.println("无考勤组");
            return leaveHours;
        }

        //判断取整方式
        float intPart = (int) leaveHours;
        float dotPart = leaveHours % 1;


        if(dotPart > 0.5){
            dotPart = (intSet == 1) ? 1.0F : 0.5F; //1为向下取整
        }
        if(dotPart < 0.5){
            dotPart = (intSet == 1) ? 0.5F : 0.0F;
        }
        leaveHours = intPart + dotPart;

        return leaveHours;
    }
    private float doCutRestTime(Date startDate, Date endDate, String restIDS, Map<String, RestTimeSettings> restTimeSettingsMap){
        String startDateString = dateUtil.dateToString(startDate);
        long leaveHoursMills = endDate.getTime() - startDate.getTime();
        //float leaveHours = dateUtil.getTimeDifference(endDate, startDate);
        if(null != restIDS){
            JSONArray ids = JSONArray.parseArray(restIDS);
            for (Object id : ids
                 ) {
                RestTimeSettings settings = restTimeSettingsMap.get(id);
                if(null != settings){
                    Date restStartDate = dateUtil.getDateByPointDate(startDateString, settings.getStartTime());
                    Date restEndDate = dateUtil.getDateByPointDate(startDateString, settings.getEndTime());
                    if(startDate.getTime() >= restEndDate.getTime() || endDate.getTime() <= restStartDate.getTime()){
                        //无需减掉休息时间的情况
                    }else{
                        //需要减掉休息时间的情况
                        //leaveHours = leaveHours - dateUtil.getTimeDifferenceByTime(restEndDate, restStartDate);
                        leaveHoursMills = leaveHoursMills - (restEndDate.getTime() - restStartDate.getTime());
                    }
                }
            }
        }
        return dateUtil.getHoursByMills(leaveHoursMills);
    }

    /**
     * 保存生产管理系统主管调整的一线生产人员额外加班调整记录
     * @param map 调整记录集合
     * @param request http请求
     * @return 标准返回值对象
     */
    @RequestMapping("/hrms/supervisor/doInsertFrontLineDayAdjustRecord")
    @ResponseBody
    public ResultEntity doInsertFrontLineDayAdjustRecord(@RequestBody Map map, HttpServletRequest request){
        ResultEntity resultEntity = new ResultEntity();
        Date opDate = new Date();
        Object staffName = request.getAttribute("staffName");
        //System.out.println(map);
        if(null != map){
            Object isPrint = map.get("isPrint");
            Object opID = map.get("op");
            Object data = map.get("dataArray");
            if(null != opID && null != data){
                JSONArray array = JSONArray.parseArray(JSON.toJSONString(data));
                //按照日期查询数据库记录，获取该日期下的所有员工调整记录并形成Map
                JSONObject orgObject = array.getJSONObject(0);
                Date date = dateUtil.formatStringToDate(orgObject.getString("dayFirstClockRecord"));
                String dateString = dateUtil.getYearByDate(date) + "-" + (dateUtil.getMonthByDate(date) < 10 ? "0" + dateUtil.getMonthByDate(date) : dateUtil.getMonthByDate(date)) + "-" + (dateUtil.getDayByDate(date) < 10 ? "0" + dateUtil.getDayByDate(date) : dateUtil.getDayByDate(date));
                //System.out.println(dateString);
                List<FrontLineDayAdjustRecord> records = iFrontLineDayAdjustRecordService.selectFrontLineDayAdjustRecordByMonth(dateString);
                Map<String, List<FrontLineDayAdjustRecord>> listMap = new HashMap<>();
                if(null != records){
                    listMap = attendanceUtil.getFrontLineDayAdjustRecordMap(records);
                }
                for (Object obj : array
                     ) {
                    JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(obj));
                    String contactID = jsonObject.getString("contactID");
                    Float moreHours = jsonObject.getFloat("moreHours");
                    Date dayFirstClockRecord = dateUtil.formatStringToDate(jsonObject.getString("dayFirstClockRecord"));
                    //先查询Map，看是否有记录，如果有，则更新，如果无，则插入
                    List<FrontLineDayAdjustRecord> userRecords = listMap.get(contactID);
                    try{
                        if(null != userRecords && userRecords.size() != 0){
                            FrontLineDayAdjustRecord userRecord = userRecords.get(0); //如果有，那么这个集合中只能有一条记录
                            userRecord.setmTime(opDate);
                            userRecord.setAdjustHours(moreHours);
                            userRecord.setOpContactId(opID.toString());
                            userRecord.setHasPrinted(Integer.parseInt(isPrint.toString()));
                            iFrontLineDayAdjustRecordService.updateFrontLineDayAdjustRecord(userRecord);
                            //System.out.println("更新了数据");
                        }else {
                            FrontLineDayAdjustRecord record = new FrontLineDayAdjustRecord();
                            record.setcTime(opDate);
                            record.setFid(UUIDUtil.createUUID());
                            record.setContactId(contactID);
                            record.setFirstCheckTimeInDay(dayFirstClockRecord);
                            record.setAdjustHours(moreHours);
                            record.setOpContactId(opID.toString());
                            record.setHasPrinted(Integer.parseInt(isPrint.toString()));
                            iFrontLineDayAdjustRecordService.insertFrontLineDayAdjustRecord(record);
                            //System.out.println("插入了数据");
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                        resultEntity.setCode("F");
                        resultEntity.setMsg("保存或更新数据时发生错误");
                        return resultEntity;
                    }
                }
            }
        }else {
            resultEntity.setCode("F");
            resultEntity.setMsg("参数传入错误");
            return resultEntity;
        }
        logUtil.insertSystemEventLog(staffName.toString(), opDate, "调整了其管辖范围内的一线生产人员额外加班记录", "考勤");
        resultEntity.setCode("S");
        resultEntity.setMsg("Success");
        return resultEntity;
    }


    /**
     * 该方法接收前端页面传来的更新打印记录，向后台做持久化操作
     * @param map 打印记录
     * @param request http请求
     * @return 标准返回值对象
     */
    @RequestMapping("/hrms/supervisor/doUpdateFrontLineVacationRecord")
    @ResponseBody
    public ResultEntity doUpdateFrontLineVacationRecord(@RequestBody Map map, HttpServletRequest request){
        ResultEntity resultEntity = new ResultEntity();
        Object opContactID = request.getAttribute("contactId");
        Object staffName = request.getAttribute("staffName");
        Date opDate = new Date();
        if(null != map){
            Object fid = map.get("fid");
            FrontLineVacationRecord record = iFrontLineVacationRecordService.selectFrontLineVacationRecordByFID(fid.toString());
            record.setHasPrinted(1);
            record.setmTime(opDate);
            record.setOpContactId(opContactID.toString());
            int i = iFrontLineVacationRecordService.updateFrontLineVacationRecord(record);
            if(i != 0){
                ContactBasic contactBasic = iContactBasicService.selectContactBasicByContactID(record.getContactId());
                logUtil.insertSystemEventLog(staffName.toString(), opDate, "打印了" + contactBasic.getStaffName() + "的请假记录", "考勤");
                resultEntity.setCode("S");
                resultEntity.setMsg("Success");
                return resultEntity;
            }
        }else {
            resultEntity.setCode("F");
            resultEntity.setMsg("参数传递错误");
            return resultEntity;
        }
        resultEntity.setCode("S");
        resultEntity.setMsg("Success");
        return resultEntity;
    }



}
